package it.webrules.deploymanager.core.st.scm.svn;

import it.webrules.deploymanager.core.st.scm.Log;
import it.webrules.deploymanager.core.st.scm.LogEntry;
import it.webrules.deploymanager.core.st.scm.LogEntryChangedPath;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

public class Svnlog2Svg {

	private final Log log;
	private final Map<Long, int[]> addedShape;
	private final String title;
	private final OutputStream outputStream;

	public Svnlog2Svg(String title, Log log, OutputStream outputStream) {
		this.title = title;
		this.log = log;
		this.outputStream = outputStream;
		this.addedShape = new HashMap<Long, int[]>();
	}

	public void addDefs(XMLStreamWriter writer) throws XMLStreamException {

		writer.writeStartElement("defs");

		writer.writeStartElement("marker");
		writer.writeAttribute("id", "startArrow");
		writer.writeAttribute("viewBox", "0 0 10 10");
		writer.writeAttribute("refX", "1");
		writer.writeAttribute("refY", "5");
		writer.writeAttribute("markerUnits", "strokeWidth");
		writer.writeAttribute("orient", "auto");
		writer.writeAttribute("markerWidth", "5");
		writer.writeAttribute("markerHeight", "4");

		writer.writeStartElement("polyline");
		writer.writeAttribute("points", "10,0 0,5 10,10 9,5");
		writer.writeAttribute("fill", "slategray");
		writer.writeEndElement();
		writer.writeEndElement();

		writer.writeStartElement("marker");
		writer.writeAttribute("id", "endArrow");
		writer.writeAttribute("viewBox", "0 0 10 10");
		writer.writeAttribute("refX", "1");
		writer.writeAttribute("refY", "5");
		writer.writeAttribute("markerUnits", "strokeWidth");
		writer.writeAttribute("orient", "auto");
		writer.writeAttribute("markerWidth", "5");
		writer.writeAttribute("markerHeight", "4");

		writer.writeStartElement("polyline");
		writer.writeAttribute("points", "0,0 10,5 0,10 1,5");
		writer.writeAttribute("fill", "slategray");
		writer.writeEndElement();
		writer.writeEndElement();

		writer.writeEndElement();

	}

	public void addHeaderAndLine(XMLStreamWriter writer) throws XMLStreamException {

		writer.writeStartElement("text");
		writer.writeAttribute("x", "130");
		writer.writeAttribute("y", "20");
		writer.writeCharacters("Tags");
		writer.writeEndElement();

		writer.writeStartElement("text");
		writer.writeAttribute("x", "350");
		writer.writeAttribute("y", "20");
		writer.writeCharacters("Trunk");
		writer.writeEndElement();

		writer.writeStartElement("text");
		writer.writeAttribute("x", "590");
		writer.writeAttribute("y", "20");
		writer.writeCharacters("Branches");
		writer.writeEndElement();

		// linea Tags
		writer.writeStartElement("line");
		writer.writeAttribute("x1", "145");
		writer.writeAttribute("y1", "30");
		writer.writeAttribute("x2", "145");
		writer.writeAttribute("y2", "5000");
		writer.writeAttribute("style", "stroke:black;stroke-width:2");
		writer.writeAttribute("stroke-dasharray", "10,10");
		writer.writeEndElement();

		// linea Trunk
		writer.writeStartElement("line");
		writer.writeAttribute("x1", "370");
		writer.writeAttribute("y1", "30");
		writer.writeAttribute("x2", "370");
		writer.writeAttribute("y2", "5000");
		writer.writeAttribute("style", "stroke:black;stroke-width:2");
		writer.writeEndElement();

	}

	private boolean isAdded(LogEntry logentry) {
		String path = logentry.changedPath.get(0).path;
		if (!path.contains("/tags/") && !path.contains("/trunk/") && !path.contains("/branches/"))
			return false;
		return true;
	}

	private boolean isCopy(LogEntry logentry) {
		if (logentry.changedPath.get(0).fromcopypath != null)
			return true;
		return false;
	}

	private void addRevision(XMLStreamWriter writer, LogEntry logentry, int idxRow) throws XMLStreamException {

		int y = 60 + (60 * idxRow);

		writer.writeStartElement("text");
		writer.writeAttribute("x", "2");
		writer.writeAttribute("y", String.valueOf(y + 3));
		writer.writeCharacters("r" + logentry.revision);
		writer.writeEndElement();

		writer.writeStartElement("line");
		writer.writeAttribute("x1", "60");
		writer.writeAttribute("y1", String.valueOf(y));
		writer.writeAttribute("x2", "5000");
		writer.writeAttribute("y2", String.valueOf(y));
		writer.writeAttribute("style", "stroke:lightgrey;stroke-width:1");
		writer.writeAttribute("stroke-dasharray", "10,5");
		writer.writeEndElement();

	}

	public void addShape(XMLStreamWriter writer, LogEntry logentry, int idxRow) throws XMLStreamException {

		int y = 45 + (60 * idxRow);
		int x = 300; // for trunk

		String style = "fill:azure;";
		String path = logentry.changedPath.get(0).path;
		String message = logentry.message;
		String author = logentry.author;
		String tooltip = "Message: " + logentry.message + "\nAuthor: " + logentry.author + "\n";

		if (message.length() > 19)
			message = message.substring(0, 17) + "...";

		if (author.length() > 22)
			author = author.substring(0, 20) + "...";

		// Commit on...
		if (path.contains("/tags/")) {

			x = 70;

			if (!isCopy(logentry)) {
				style = "fill:tomato;";
				tooltip = "WARNING: Commit on tags!!\n\n" + tooltip;
			}

		} else if (path.contains("/branches/")) {

			x = 475;

		} else {

		}

		for (LogEntryChangedPath logEntryChangedPath : logentry.changedPath) {
			tooltip += logEntryChangedPath.type + " " + logEntryChangedPath.path + "\n";
		}

		addedShape.put(logentry.revision, new int[] { x, y });
		writer.writeStartElement("svg");
		writer.writeAttribute("x", String.valueOf(x));
		writer.writeAttribute("y", String.valueOf(y));

		writer.writeStartElement("title");
		writer.writeCharacters(tooltip);
		writer.writeEndElement();

		writer.writeStartElement("rect");
		writer.writeAttribute("x", "0");
		writer.writeAttribute("y", "0");
		writer.writeAttribute("width", "135");
		writer.writeAttribute("height", "32");
		writer.writeAttribute("rx", "10");
		writer.writeAttribute("ry", "10");
		writer.writeAttribute("style", style + "stroke-width:1;stroke:rgb(0,0,0)");
		writer.writeEndElement();

		writer.writeStartElement("text");
		writer.writeAttribute("x", "5");
		writer.writeAttribute("y", "15");
		writer.writeAttribute("font-family", "Verdana");
		writer.writeAttribute("font-size", "12");
		writer.writeCharacters(message);
		writer.writeEndElement();

		writer.writeStartElement("text");
		writer.writeAttribute("x", "10");
		writer.writeAttribute("y", "28");
		writer.writeAttribute("font-family", "Verdana");
		writer.writeAttribute("font-size", "9");
		writer.writeCharacters(author);
		writer.writeEndElement();

		writer.writeEndElement();

	}

	public void addLink(XMLStreamWriter writer, LogEntry logentry, int idxRow) throws XMLStreamException {

		String fromPath = logentry.changedPath.get(0).fromcopypath;
		Long fromRev = logentry.changedPath.get(0).fromrevision;

		int x1;
		int y1;
		int x2;
		int y2;

		if (addedShape.containsKey(fromRev)) {
			// from a shape

			int[] from = addedShape.get(fromRev);
			x1 = from[0] - 1;
			y1 = from[1] + 15;
			x2 = 212;
			y2 = 45 + (60 * idxRow);

		} else {
			// from external paint

			x1 = 45;
			y1 = 35 + (60 * idxRow);
			x2 = x1 + 17;
			y2 = y1 + 12;

			writer.writeStartElement("text");
			writer.writeAttribute("x", String.valueOf(x1 - 15));
			writer.writeAttribute("y", String.valueOf(y1 - 2));
			writer.writeAttribute("font-family", "Verdana");
			writer.writeAttribute("font-size", "9");
			writer.writeCharacters(fromPath + ", r" + fromRev);
			writer.writeEndElement();

		}

		writer.writeStartElement("line");
		writer.writeAttribute("x1", String.valueOf(x1));
		writer.writeAttribute("y1", String.valueOf(y1));
		writer.writeAttribute("x2", String.valueOf(x2));
		writer.writeAttribute("y2", String.valueOf(y2));
		writer.writeAttribute("stroke", "slategray");
		writer.writeAttribute("stroke-width", "3");
		writer.writeAttribute("marker-end", "url(#endArrow)");
		writer.writeEndElement();

	}

	public void generateGraph() throws XMLStreamException, IOException {

		XMLOutputFactory output = XMLOutputFactory.newInstance();

		XMLStreamWriter writer = output.createXMLStreamWriter(outputStream);

		writer.setPrefix("xlink", "http://www.w3.org/1999/xlink");
		writer.setDefaultNamespace("http://www.w3.org/2000/svg");

		writer.writeStartElement("svg");
		writer.writeDefaultNamespace("http://www.w3.org/2000/svg");
		writer.writeNamespace("xlink", "http://www.w3.org/1999/xlink");
		writer.writeAttribute("version", "1.1");

		writer.writeStartElement("title");
		writer.writeCharacters(title);
		writer.writeEndElement();

		addDefs(writer);
		addHeaderAndLine(writer);

		int idxRow = 0;
		for (LogEntry logentry : log.entries) {

			if (isAdded(logentry)) {
				addRevision(writer, logentry, idxRow);
				addShape(writer, logentry, idxRow);
				if (isCopy(logentry))
					addLink(writer, logentry, idxRow);
				idxRow++;
			}

		}

		writer.writeEndElement();

		writer.flush();
		outputStream.close();
	}

	public void openSvg(File file) throws IOException {
		String[] browsers = { "epiphany", "google-chrome", "firefox", "mozilla", "konqueror", "netscape", "opera", "links", "lynx" };

		StringBuffer cmd = new StringBuffer();
		for (int i = 0; i < browsers.length; i++)
			cmd.append((i == 0 ? "" : " || ") + browsers[i] + " " + file.getAbsolutePath());

		Runtime rt = Runtime.getRuntime();
		rt.exec(new String[] { "sh", "-c", cmd.toString() });

	}
}
